package gui;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;

import multiThreading.DataFabThread;

import dbConnection.Database;

public class DataGenerator extends JPanel {


    private static final long serialVersionUID = 1176298038262194550L;
	private Database DB;
	private ResultsPanel results;
	
	//strings for random generation
	private String[] sideEffects = {"bleeding","shakes","diarrhea","vomiting","nausea","death","blurry vision",
		"insomina","ulcers","irritability","paranoia","arachnaphobia","nightmares","inebriation","levitation",
		"drowning","labored breathing","pregnancy","drooling","super powers"};
	private String[] medNouns = {"warts","discoloration","bruising","dry skin","shaking","bleeding","pus","ulcer",
		"toenails","tooth","cat hair","blood","odor","scarring","elephant","hematoma","contusion","adhesion","growth","lesion","pustule","carbuncle","bubos","louse","worm"};
	private String[] bodyParts = {"leg","foot","arm","hand","skin","liver","head","groin","fingernail",
		"toe","stomach","throat","back","neck","beard","chest","ankle","tongue","nose","imagination"};
	private String[] adjectives = {"green","orange","pink","fabulous","scaly","dried","slimy","itchy","painful",
		"recurring","nightmarish","eldritch","abominable","large","small","ingrown","blue","white","black","clear","red","sentient", "pervasive"};
	private String[] prepositions = {"on","below","behind","inside","covering","in place of"};
	private String[] diseases = {"cancer","lung cancer","fever","flu","mumps","plague","paranoia","hypochondria","hypothyroidism",
		"malaria","tapeworms","migraines","pinkeye","allergies","paranoia","hernia","delusions","lycanthropy", "gunshot wound",
		"GI Bleed", "anemia","scabies","lice","leukemia","septesemia","dehydration","flu","headache","meningitis","blindness","trauma","gout","gangrene"};
	private String[] consonants = {"b", "c", "ck", "ct", "cc", "d", "dd", "f", "g", "h", "j", "k", "kk", "l", "ll", "m", "n", "nt", "nk", "ng","nm",
		"p", "pt", "pn", "pp","pc","pd", "pf","ph","pl","qu","r","rd","rc","rg","rk","rm","rn","rp","rs","rt","rv","s","ss","sk","sm","sn","st",
		"sv","t","v","w","x","z"};
	private String[] vowels = {"a", "e", "ae", "i", "ai", "o", "ou", "eo", "u","uy","y"};
	private ArrayList<String> names;
	
	
	//combo box fields
	public static String[] comboBoxFields = {"diagnosis","drug","drug interaction","patient","patient allergies","patient takes","vitals"};
	private String[] numbers = {"1", "5", "10", "20", "50","100","5000"};
	private boolean debug = false;
	
	/**
	 * Initializes database
	 * @param DB The database connection
	 * @param results reference to panel containing graph, where we can show newly generated data
	 */
	public DataGenerator(Database DB, final ResultsPanel results) {
		this.DB = DB;
		this.results = results;
		names = new ArrayList<String>();
		
		setLayout(new GridLayout(2,1));
		
		final JComboBox<String> tables = new JComboBox<String>(comboBoxFields);
		
		JLabel tableLabel = new JLabel(" records in ");
		JLabel numberLabel = new JLabel("Generate ");
		final JComboBox<String> numSelect = new JComboBox<String>(numbers);
		
		final JTextArea queryResults = new JTextArea();
		queryResults.setEditable(false);
		queryResults.setLineWrap(true);
		
		JButton fabricate = new JButton("Fabricate");
		fabricate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
			    (new Thread(new DataFabThread(DataGenerator.this,tables.getSelectedIndex(),Integer.parseInt((String) numSelect.getSelectedItem()),queryResults))).start();
			    //generateData(Integer.parseInt((String) numSelect.getSelectedItem()), tables.getSelectedIndex(), queryResults);
			}
		});
		
		final JCheckBox debugBox = new JCheckBox();
		debugBox.addActionListener(new ActionListener() {
		   public void actionPerformed(ActionEvent e) { 
		       debug = (debugBox.getSelectedObjects()==null)?false:true;
		   }
		});
		debugBox.setSelected(false);
		JLabel debugLabel = new JLabel("Debug");
		
		final JCheckBox truncateAll = new JCheckBox();
		
		JButton truncate = new JButton("Truncate");
		truncate.addActionListener(new ActionListener() {
		    public void actionPerformed(ActionEvent e) {
			if (truncateAll.isSelected()) {
			    for(int i = 0; i < comboBoxFields.length;i++) {
				results.sqlUpdate("DELETE FROM patient");
				results.sqlUpdate("DELETE FROM drug");
			    }
			} else {
			    results.sqlUpdate("DELETE FROM " + comboBoxFields[tables.getSelectedIndex()]);
			}
			results.sqlQuery("SELECT * FROM " + comboBoxFields[tables.getSelectedIndex()].replaceAll("\\s", ""));
			queryResults.setText("Purge Successful");
		    }
		});
		
		JPanel commandPanel = new JPanel();
		commandPanel.add(numberLabel);
		commandPanel.add(numSelect);
		commandPanel.add(tableLabel);
		commandPanel.add(tables);
		commandPanel.add(debugBox);
		commandPanel.add(debugLabel);
		commandPanel.add(fabricate);
		commandPanel.add(truncate);
		commandPanel.add(truncateAll);
		commandPanel.add(new JLabel("All"));

		add(commandPanel);
		add(queryResults);
	}
	
	/** generates numRecords results in table.  Places execution results in queryResults*/
	public void generateData(int numRecords, int table, JTextArea queryResults) {
		String query = "";
		for(int i = 0; i < numRecords; i++) {
			switch(table) {
			case (0): //diagnosis
			    query = "INSERT INTO diagnosis (PID,Description,date,diagnosisName,Active) VALUES (" + getRandomPID() + 
			    	",'Found " + getWord(adjectives) + ' ' + getWord(medNouns) + ' ' +  getWord(prepositions) + " patient\\'s " + getWord(bodyParts) + 
			    	".'," + randomDate() + ",'" + getWord(diseases)+ "', " + System.currentTimeMillis()%2 + ");";
				break;
			case (1): //drug
			    query = "REPLACE INTO drug (sideEffects,name) VALUES ('" + getSideEffects() + "','" + getDrugName() + "');";
				break;
			case(2): //drug interaction
			    int drug1 = getRandomDrugID();
				int drug2 = getRandomDrugID(drug1);
				query = "REPLACE INTO druginteraction (drugID1,drugID2,interaction) VALUES(" + drug1 + "," + drug2 + ",'" + getWord(sideEffects) + "');";
			    	break;
			case(3): //patient
			    if (names.size() == 0) {
				initializeNames();
			    }
			    query = "INSERT INTO patient (smoker,name,gender,dob) VALUES (" + 
				    System.currentTimeMillis() % 2 + ",'" + 
				    names.get((int) (names.size() * Math.random())) + "','" + 
				    ((System.currentTimeMillis() % 2 == 1)?"male":"female") + "'," + 
				    randomBirthDate() + ");";
				break;
			case(4): //patient allergies
			    query = "REPLACE INTO patientallergies (PID,drugID) VALUES (" + getRandomPID() + "," + getRandomDrugID() + ");";
				break;
			case(5): //patient takes
			    query = "REPLACE INTO patienttakes (PID,drugID) VALUES (" + getRandomPID() + "," + getRandomDrugID() + ");";
				break; 
			case(6): 
			    query = "INSERT INTO vitals (PID,date,time,respirationRate,pulse,bloodPressure,weight,height) VALUES(" + 
				    getRandomPID() + "," + 
				    randomDate() + ",'" + 
				    (int)(Math.random()*24) + ':' + (int) Math.random() * 60 + "'," + //time
				    (int)(Math.random() * 18 + 12) +  "," + //respiration rate
				    (int)(Math.random() * 100 + 50) + ",'" + //pulse
				    (int)(Math.random() * 65 + 75) + "/" + (int)(Math.random() * 40 + 50) + "','" + //bp
				    (int)(Math.random() * 100 + 30) + "." + (int)(Math.random()*100) + //weight
				    "','1." + (int)(Math.random() * 100) + "')";//height: IN METERS!
				break; //vitals
			}
			try {
			    if (debug) {
				    System.out.println(query);
			    }
			    DB.con.prepareStatement(query).executeUpdate();	
			    queryResults.setText("Successfully added records to " + comboBoxFields[table]);
			} catch (SQLException e) {
			queryResults.setText(e.toString());
		    }
		}
		results.sqlQuery("SELECT * FROM " + comboBoxFields[table].replaceAll("\\s", ""));
	}
	/** returns a random word from an array of words */
	private String getWord(String[] wordList) {
	    return wordList[(int)(Math.random()*wordList.length)];
	}
	
	/** Generates a random date in YYYY-MM-DD format, starting from 1990 */
	private String randomDate() {
	    return "'" + (int)(1990 + Math.random() * 23) + "-" + (int)(Math.random() * 12 + 1) + "-" + (int)(Math.random() * 28 + 1) + "'";
	}
	
	/** Generates a random date in YYYY-MM-DD format, starting from 1900 */
	private String randomBirthDate() {
	    return "'" + (int)(1900 + Math.random() * 100) + "-" + (int)(Math.random() * 12 + 1) + "-" + (int)(Math.random() * 28 + 1) + "'";
	}
	
	/** concatenates a random number of side effects, weighted towards lower numbers of side effects */
	private String getSideEffects() {
	    StringBuilder sb = new StringBuilder();
	    for(int i=2; i < System.currentTimeMillis() % 6; i++) { //if modulo is 0,1, or 2, no side effects
			String sideEffect = getWord(sideEffects);
			if (!sb.toString().contains(sideEffect)) {;
			    sb.append(sideEffect);
			    sb.append(", ");
			}
	    }
	    
	    if (sb.toString().equals("")) {
		return "none";
	    } else {
		sb.deleteCharAt(sb.length() - 1);
		sb.deleteCharAt(sb.length() - 1);
	    }
	    return sb.toString();
	}
	
	/** generates a drug name from random consonant and vowel sounds */
	private String getDrugName() {
	    StringBuilder sb = new StringBuilder();
	    for (int i = (int) (System.currentTimeMillis()%2);i < 4 + System.currentTimeMillis()%3; i++) {
		if (i%2 == 0) {
		    sb.append(getWord(consonants));
		} else {
		    sb.append(getWord(vowels));
		}
	    }
	    return sb.toString();
	}
	
	/** Returns a random patient ID */
	private int getRandomPID() {
	    int pid = -1;
	    try {
		ResultSet rs = DB.con.prepareStatement("SELECT PID FROM patient ORDER BY RAND() LIMIT 1").executeQuery();
		rs.next();
		pid = (int) rs.getObject(1);
	    } catch (SQLException e) {
		    e.printStackTrace();
	    }
	    return pid;
	}
	
	/** Returns a random drug ID */
	private int getRandomDrugID() {
	    return getRandomDrugID(-1);
	}
	
	/** Returns a random drug ID except for the provided exception */ 
	private int getRandomDrugID(int exception) {
	    int drugID = -1;
	    try {
		ResultSet rs = DB.con.prepareStatement("SELECT drugID FROM drug WHERE drugID != " + exception + " ORDER BY RAND() LIMIT 1;").executeQuery();
		rs.next();
		drugID = (int) rs.getObject(1);
	    } catch (SQLException e) {
		e.printStackTrace();
	    }
	    return drugID;
	}
	
	/** If names aren't yet read into memory, read from names.txt */
	private void initializeNames() {
	    try {
		String name = "";
		Reader reader = new InputStreamReader(DataGenerator.class.getResourceAsStream("names.txt"),"utf-8");
		BufferedReader nameReader = new BufferedReader(reader);
		while (name != null) {
		    name = nameReader.readLine();
		    if (name != null) {
			names.add(name);
		    }
		}
		
	    } catch (UnsupportedEncodingException e) {
		e.printStackTrace();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}
}
